/**
 * @param entities
 * @param func
 */

function getProperty(entities = [], func) {
  const ids = entities.map(value => {
    return func(value);
  }).filter(Boolean);
  return [...new Set(ids)];
}

/**
 * @param {any[] } entities
 * @param {any[] } dbEntities
 * @param {function(dbEntity:any,entity:any):boolean} match
 * @param {function(dbEntity:any,entity:any):any} set
 * @param {function(entity:any)} notFoundProcess
 * @param {{match,set}[]} moreMatchAndSet
 */
function setProperty(
  entities,
  dbEntities,
  match,
  set,
  notFoundProcess = null,
  moreMatchAndSet = []
) {
  function process(entity, index, match, set) {
    const dbEntity = dbEntities.find(dbEntity => match(dbEntity, entity));
    if (dbEntity) {
      const r = set(dbEntity, entity);
      if (r) {
        entities[index] = r;
      }
    } else if (notFoundProcess) {
      notFoundProcess(entity);
    }
  }

  for (let index in entities) {
    let entity = entities[index];
    process(entity, index, match, set);
    if (moreMatchAndSet.length > 0) {
      for (let {match, set} of moreMatchAndSet) {
        process(entity, index, match, set)
      }
    }
  }
}

/**
 * @param {any[] } entities
 * @param {any[] } dbEntities
 * @param {function(dbEntity:any,entity:any):boolean} match
 * @param {function(filter:any[],entity:any):any} set
 */
function setProperties(
  entities,
  dbEntities,
  match,
  set,
) {
  for (let entity of entities) {
    const filter = dbEntities.filter(dbEntity => match(dbEntity, entity));
    set(filter, entity)
  }
}

function groupBy(arr = [], func) {
  const map = new Map()
  arr.forEach(item => {
    const key = func(item)
    if (!map.has(key)) {
      map.set(key, [])
    }
    map.get(key).push(item)
  })
  return map;
}

function listToMap(arr = [], keyFunc, valFunc) {
  const map = new Map()
  arr.forEach(value => {
    const key = keyFunc(value);
    const val = valFunc(value);
    map.set(key, val)
  })
  return map;
}

module.exports = {
  setProperty,
  getProperty,
  setProperties,
  groupBy,
  listToMap
};